home *** CD-ROM | disk | FTP | other *** search
- /********************************************************************
- * Popup window toolkit for Turbo C (popup.c) *
- ********************************************************************/
- #include <stddef.h>
- #include <stdarg.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <alloc.h>
- #include <conio.h>
- #include <string.h>
- #include <process.h>
- #include "\tc\myincs\popup.h"
- #include "\tc\myincs\mouse.h"
- #define MAX(a,b) ((a) > (b) ? (a) : (b))
- #define MIN(a,b) ((a) < (b) ? (a) : (b))
- /*
- * Global data definitions
- */
- windesc *base_win = NULL; /* The "Base Window" pointer */
- windesc *curr_win = NULL; /* The current window pointer */
-
- /* Color sets for color monitors */
- /* {border_type, border_color, text_color, title_color, hilite_color} */
- wincolors defcolors = {1, 23, 30, 27, 94 };
- wincolors invcolors = {1, 112, 112, 112, 15 };
- wincolors monocolors = {1, 7, 15, 15, 12 };
- wincolors errcolors = {1, 79, 79, 79, 4 };
- wincolors msgcolors = {1, 47, 47, 46, 112 };
- wincolors graycolors = {1, 116, 127, 127, 127 };
-
- /* variables internal to popup.c */
- static windesc *top_win; /* window stack pointer */
- static void chg_win(windesc *this);
- static windesc *make_window_node(void);
- static windesc *push_window_node(void);
- static void dispose_window_node(windesc *w);
-
- void init_win(void)
- /* init_win initializes the internal variables for the popup windows
- package. This function creates a base window "base_win" which
- represents the entire screen.
- This function MUST be called before any popup routines are used. */
- {
- struct text_info ti; /* Turbo C predefined structure */
-
- base_win = make_window_node(); /* allocate a window node */
- gettextinfo(&ti); /* get base window coords */
- base_win->xul = ti.winleft - 1; /* but our coords include border ! */
- base_win->xlr = ti.winright + 1;
- base_win->yul = ti.wintop - 1;
- base_win->ylr = ti.winbottom + 1;
- base_win->wd = ti.screenwidth + 2;
- base_win->ht = ti.screenheight + 2;
- base_win->xsave = ti.curx;
- base_win->ysave = ti.cury;
- base_win->wc = monocolors; /* default to monochrome colors */
- base_win->wc.text_color = ti.attribute;/* but use current window color */
- base_win->name = "base"; /* window has no title */
- base_win->wtype = tile; /* no saved image underneath */
- base_win->wc.border_type = 0; /* has no border either */
- top_win = base_win; /* set up window stack */
- curr_win = base_win;
- }
-
- windesc *draw_win(int x,int y,int wd, int ht, char *title,
- enum windowtype wt, wincolors *wc)
- /* draw_win creates a new window at a designated screen location.
- All window coordinates include the border! Note that the
- turbo-C window funciton does not know about the border, and that
- its coordinates are actually "inside" the border.
- Besides the usual coordinates for (x,y), you can use the following
- codes:
- x = CTRWIN (Center window in x direction)
- y = CTRWIN (Center window in y direction)
- */
- {
- windesc *w;
- int xsave, ysave;
- mouse_off(1); /* hide mouse cursor during screen updates */
- w = push_window_node(); /* create and link up a window node */
-
- /* check for valid window size */
- wd = MAX(wd,3);
- wd = MIN(wd,80);
- ht = MAX(ht,3);
- ht = MIN(ht,25);
-
- /* check for centering coordinates and current coordinates.
- Reminder: these are absolute coordinates ! */
- if (x == CTRWIN) x = (80-wd) /2;
- if (y == CTRWIN) y = (25-ht) /2;
-
- /* Check for valid coordinates. Coordinates (0,0) are valid only for
- borderless windows, (the actual window will start at (1,1)). */
- if (wc->border_type) {
- x = MAX(x,1);
- y = MAX(y,1);
- }
- else {
- x = MAX(x,0);
- y = MAX(y,0);
- }
- if ((x+wd) > 80) x = 80-wd+1;
- if ((y+ht) > 25) y = 25-ht+1;
-
- /* store the window parameters */
- w->wd = wd; w->ht = ht; w->xul = x; w->yul = y;
- w->xlr = x + w->wd-1; w->ylr = w->yul + w->ht -1;
- w->wc = *wc; /* set up our set of colors */
- w->xsave = 1; w->ysave = 1;
- w->wtype = wt; w->name = strdup(title);
-
- /* allocate and save image underneath if a popup window */
- if (wt == popup) {
- w->image = calloc(wd*ht,2);
- swap_image(w);
- }
-
- /* Ready to draw box and title. To do this we must be in base or
- "absolute" coords. But we must be careful to save the base cursor
- coords cause draw box and centerstr will change them on us. */
- if (curr_win == base_win) {
- xsave = wherex();
- ysave = wherey();
- }
- else {
- xsave = base_win->xsave;
- ysave = base_win->ysave;
- }
- chg_win(base_win);
- draw_box(w->xul,w->yul,w->xlr,w->ylr,w->wc.border_type,w->wc.border_color);
- centerstr(w->xul,w->yul,w->xlr,w->yul,w->name,w->wc.title_color);
- gotoxy(xsave,ysave); /* restore base window cursor coords */
- chg_win(w); /* Now select new window */
- clr_win(); /* and clear it */
- mouse_on(1); /* restore mouse state */
- return w; /* return new window pointer */
- }
-
- void view_win(windesc *this, int select)
- /* If select = 1, then view_win moves "this" window to the
- top of the stack and makes it the active window.
- If select = 0, then the window is removed from the stack and erased.
- Node that no moves take place if already at the top.
- If this is merely a tiled window, then it is just selected. */
- {
- windesc *p;
- if (select && this == top_win) return;
- mouse_off(1); /* make sure mouse is hidden */
-
- /* if this is a popup window, move its image to the top */
- if (this->wtype == popup) {
- p = top_win;
- while (p != this) { /* hide all window above */
- swap_image(p);
- p = p->under;
- }
- swap_image(this); /* and then this window */
- p = this; /* then put rest of windows back */
- while(p != top_win) {
- p = p->over;
- swap_image(p);
- }
- }
-
- /* link up window underneath this one, with the window above it */
- if (this == top_win) { /* if this == top_win here, then it is also */
- this->under->over = NULL; /* true that we're removing it for good */
- top_win = this->under;
- }
- else {
- this->under->over = this->over;
- this->over->under = this->under;
- }
- if (select) {
- top_win->over = this; /* move window to the top */
- this->under = top_win;
- top_win = this;
- swap_image(this); /* put back it's image. Does nothing if tiled */
- chg_win(this); /* change window */
- }
- else {
- chg_win(top_win); /* might as well select top window */
- dispose_window_node(this); /* but do before free old window */
- }
- mouse_on(1); /* restore mouse state */
- }
-
- static void chg_win(windesc *this)
- /* internal routine to select a window */
- {
- curr_win->xsave = wherex();
- curr_win->ysave = wherey();
- window(this->xul+1, this->yul+1, this->xlr-1, this->ylr-1);
- textattr(this->wc.text_color); /* restore window color and cursor */
- gotoxy(this->xsave, this->ysave);
- curr_win = this; /* selected window is active */
- }
-
- void swap_image(windesc *w)
- /* This routine swaps the image buffer of a window with what is on the
- screen. If the window is not a popup window, then nothing happens. */
- {
- int xstart, ystart, xfin, yfin;
- char *temp_image;
- unsigned int nbytes;
- if (w->wtype == popup) {
- xstart = w->xul; ystart = w->yul;
- xfin = w->xlr; yfin = w->ylr;
- if (!w->wc.border_type) { /* don't swap border area if no border */
- xstart++; ystart++;
- xfin--; yfin--;
- }
- nbytes = (xfin-xstart+1)*(yfin-ystart+1)*2;
- mouse_off(1); /* hide cursor during screen update */
- temp_image = malloc(nbytes);
- gettext(xstart, ystart, xfin, yfin, temp_image);
- puttext(xstart, ystart, xfin, yfin, (void *)w->image);
- memcpy(w->image, temp_image, nbytes);
- free(temp_image);
- mouse_on(1); /* restore mouse cursor */
- }
- }
-
- void clr_win(void)
- /* High level clear window. Supports the mouse cursor, and uses
- the text_color of the current window when clearing it. */
- {
- mouse_off(1);
- textattr(curr_win->wc.text_color);
- clrscr();
- mouse_on(1);
- }
-
- void mprintf(char *fmt,...)
- /* mprintf is a high level printf-like funciton that calls printf (so it
- knows about the current window), but also takes care of them mouse.
- NOTE: the formatting must not exceed 255 characters ! */
- {
- va_list arg_ptr;
- char t[255];
- va_start(arg_ptr,wd);
- vsprintf(t,fmt,arg_ptr); /* internal format function */
- mouse_off(1); /* hide mouse cursor during screen update */
- cprintf("%s", t); /* print the string with scrolling supported */
- mouse_on(1); /* restore mouse cursor */
- va_end(arg_ptr);
- }
-
- void prtfstr(int x, int y, char *fmt, unsigned char attr, int wd,...)
- /* prtfstr prints a formatted string in the current window. prfstr is
- similar to cprintf except that it doesn't support wrap-around, in fact,
- it goes to great lengths to get around it. If the string is too long
- to fit in the window, it will be truncated.
- If attr != 0, the string will be printed with that color, otherwise
- the color will be left alone.
- If wd < 0 and the length of the formatted string = 1, then prtfstr
- will print the one-character string abs(wd) times. This is useful
- for filling a line with a character.
- NOTE: The formatting must not exceed 255 characters ! */
- {
- va_list arg_ptr;
- char t[255];
- int len, i, n, xa, ya, fillflag;
- static texel line[80]; /* text image buffer */
- va_start(arg_ptr,wd);
- vsprintf(t, fmt, arg_ptr); /* internal format function */
- va_end(arg_ptr);
- n = abs(wd); /* compute and bounds check desired width */
- n = MIN(n, curr_win->wd-x-1);
- xa = curr_win->xul + x;
- ya = curr_win->yul + y;
- len = MIN(strlen(t), n); /* keep string inside the window */
- t[len] = 0; /* by truncating if necessary */
- if (len) { /* only do non-null strings */
- if (wd < 0 && (strlen(t) == 1)) {
- fillflag = 1;
- len = n;
- }
- else {
- fillflag = 0;
- }
- mouse_off(1); /* remember to hide mouse */
- gettext(xa, ya, xa+len-1, ya, line); /* extract text image */
- for (i=0; i<len; i++) {
- if (fillflag) line[i].ch = *t;
- else line[i].ch = t[i];
- if (attr) line[i].attr = attr;
- }
- puttext(xa, ya, xa+len-1, ya, line); /* put it back */
- mouse_on(1); /* restore mouse */
- if (x+len == curr_win->wd-1)
- x--; /* Keep cursor in window */
- gotoxy(x+len, y); /* then move it to end of string */
- }
- else { /* for null strings, just move cursor */
- gotoxy(x,y);
- }
- }
-
- void centerstr(int xul, int yul, int xlr, int ylr, char *s, unsigned char a)
- /* centerstr prints a string centered between the relative coord's
- (xul,yul) and (xlr,ylr), with attribute a. */
- {
- int xs, ys, wd;
- if (*s != 0) {
- mouse_off(1);
- wd = xlr-xul+1;
- if ((xs = (wd-strlen(s)) / 2 + xul) < xul) xs = xul;
- if ((ys = (ylr-yul+1) / 2 + yul) < yul) ys = yul;
- prtfstr(xs, ys, s, a, wd);
- mouse_on(1);
- }
- }
-
- void draw_box(int xul, int yul, int xlr, int ylr, int btype, int attr)
- /* Draws a box at the upper left (xul,yul) and lower right
- (xlr,ylr) coords with given attribute. If btype = 0, no box is drawn,
- if btype = 1, a single line box is drawn, if btype = 2, a doulble line
- box is drawn.
- */
- {
- static int boxcar[2][6] = /* graphics characters for a box */
- {
- {218,196,191,179,192,217}, /* single line box */
- {201,205,187,186,200,188} /* double line box */
- };
- int i, hzchar, vtchar, oldattr;
- texel t;
- struct text_info ti;
- if (btype)
- {
- mouse_off(1);
- gettextinfo(&ti); /* save old text attribute */
- oldattr = ti.attribute;
- textattr(attr);
- hzchar = boxcar[btype-1][1];
- vtchar = boxcar[btype-1][3];
- /* draw top and bottom sides */
- gotoxy(xul+1,yul);
- for (i = xul+1; i < xlr; i++) putch(hzchar);
- gotoxy(xul+1,ylr);
- for (i = xul+1; i < xlr; i++) putch(hzchar);
- /* draw vertical sides */
- for (i = yul+1; i < ylr; i++)
- {
- gotoxy(xul,i);
- putch(vtchar);
- gotoxy(xlr,i);
- putch(vtchar);
- }
- /* draw corners */
- gotoxy(xul,yul); putch(boxcar[btype-1][0]); /* upper left */
- gotoxy(xlr,yul); putch(boxcar[btype-1][2]); /* upper right */
- gotoxy(xul,ylr); putch(boxcar[btype-1][4]); /* lower left */
- /* can't write lower right corner via putch, due to possible
- scroll problems, so must do it a roundabout way */
- gettext(xlr,ylr,xlr,ylr,&t);
- t.ch = boxcar[btype-1][5];
- t.attr = attr;
- puttext(xlr,ylr,xlr,ylr,&t);
- textattr(oldattr); /* restore old attribute */
- mouse_on(1);
- }
- }
-
- static windesc *make_window_node(void)
- /* make_window_node allocates room for a new window structure,
- and initializes it's links to NULL. */
- {
- windesc *q;
- q = (windesc *)malloc(sizeof(windesc));
- q->image = NULL;
- q->under = NULL;
- q->over = NULL;
- return q;
- }
-
- static windesc *push_window_node(void)
- /* push_window_node "pushes" the window w onto the window stack. */
- {
- windesc *q;
- q = make_window_node(); /* allocate a window node */
- top_win->over = q; /* link top of stack to new node */
- q->under = top_win; /* link lew node to top of stack */
- top_win = q; /* set top of stack to new node */
- return q;
- }
-
- static void dispose_window_node(windesc *w)
- /* Dispose_window_node frees up the image save area of the window,
- and the window structure itself. */
- {
- if (w != NULL) { /* savety test for base window */
- if (w->wtype == popup) free(w->image);
- free(w->name); /* free up window title */
- free(w); /* and then the structure itself */
- }
- }